Key Point
- 리액트 재조정 과정에서 변경을 감지하는 방식
- DOM 엘레멘트를 재사용한다.
내용
1const Form = () => {
2const [isCompany, setIsCompany] = useState(false);
3
4 return (
5 <>
6 {/* checkbox somewhere here */}
7
8 { isCompany ? (
9 <Input id="company-tax-id-number" placeholder="Enter you company Tax ID" ... />
10 ):(
11 <Input id="person-tax-id-number" placeholder="Enter you personal Tax ID" ... /> )
12 }
13 </>
14 )
15}
리액트에 CreateElement로 생성된 객체는 type, props, ref, key가 있다.
id는 단순히 DOM 엘리먼트의 속성으로 새로운 엘리먼트를 생성해서 추가할 필요가 없다.
diffing과정에서 이전의 DOM을 유지하면서 javascript로 DOM 속성을 변경만 해준다.
따라서 위 결과에서는 id, placeholder는 바뀌지만 입력된 text는 유지된다.
위 결과에서 입력된 text를 유지하지 않도록 해보자
1const Form = () => {
2const [isCompany, setIsCompany] = useState(false);
3
4 return (
5 <>
6 {/* checkbox somewhere here */}
7
8 { isCompany ? (
9 <Input id="company-tax-id-number" placeholder="Enter you company Tax ID" ... />
10 ): null
11 }
12
13 { !isCompany ? (
14 <Input id="company-tax-id-number" placeholder="Enter you company Tax ID" ... />
15 ): null
16 }
17 </>
18 )
19}
위 동작은 Form의 children 배열에서 [checkbox, null, Input]
과 같이 객체가 생성되고, 배열 순으로 엘레멘트를 검사하기 때문에 DOM 엘레멘트를 새로 그리게 된다.
- [Checkbox, null, Input]
- [Checkbox, Input, null]
다른 방법으로 key를 사용할 수 있다. 서로 다른 key를 전달한다면 재조정에서 type 외에 key보고 리렌더링을 진행한다. “state reset”이라고도 한다는데 뭐 굳이..
Key
type만 비교해서 달라진것을 찾는다면 반복문을 통해서 여러 하위 컴포넌트를 사용할 수 없다.
1const data = ['1', '2', ~];
2
3const Component = () => {
4 // "key" is mandatory here!
5 return data.map((value) => <Input id={value} key={value} />);
6};
위 컴포넌트에서 key가 없다면 Input의 순서가 달라져도 알 수 없기 때문에 DOM 엘레멘트는 유지되면서 속성만 바뀐다. key를 통해서 생선된 인스턴스를 구분하고 재사용한다.
memoization한 컴포넌트와 key를 index로 할 때, 유니크한 문자로 할 때
1const data = [
2 { id: 'business', placeholder: 'Business Tax' },
3 { id: 'person', placeholder: 'Person Tax' },
4];
5
6const InputMemo = React.memo(Input);
7
8const Component = () => {
9 // array's index is fine here, the array is static
10
11 return data.map((value, index) => (
12 <InputMemo
13 key={index}
14 placeholder={value.placeholder}
15 />
16 ));
17};
위 예제는 순서가 바뀐다고 하면 Input이 memo 되어 있어도 리렌더링된다.
key가 index로 되어있기 때문에 0번째 Input에 id, placeholder가 변경된 것이기 때문에 리렌더링된다.
key를 id로 한다면 이전에 사용한 DOM을 그대로 사용하기 때문에 리렌더링이 발생하지 않는다.
컴포넌트 내부에서 컴포넌트를 정의하는 것이 왜 안티패턴인지
1const Component = () => {
2 const Input = () => <input />;
3
4 return <Input />;
5};
재조정 과정에서 Type을 검사할 때, 매번 다른 Input 함수를 비교하게 된다.
매번 DOM 엘레멘트를 지우고 새로 만들게 되고, 컴포넌트가 무거우면 깜빡거리는 문제도 발생할 수 있다.